package com.linh.trade.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import javax.swing.JPanel;

import com.linh.trade.Trade;
import com.linh.trade.Trade.Direction;
import com.linh.trade.Trade.State;
import com.linh.trade.TraderActionListener;
import com.linh.trade.data.NewPointListener;
import com.linh.trade.data.Point;

public class Graph extends JPanel implements NewPointListener,
		TraderActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private List<Point> points;
	private Map<Point, Trade> map;

	private int maxNoOfPoints;
	
	private PointAdder pointAdder;

	public Graph(int maxNoOfPoints) {
		super();
		this.maxNoOfPoints = maxNoOfPoints;
		points = new ArrayList<Point>();
		map = new HashMap<Point, Trade>();
		setPreferredSize(new Dimension(800, 250));
		pointAdder=new PointAdder();
		new Thread(pointAdder).start();
	}

	public void addPoint(Point p) {

		pointAdder.queue(p);
		repaint();
	}

	public void clear() {
		points.clear();
		map.clear();
		pointAdder.clear();
		repaint();
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		int w = this.getWidth();
		int h = this.getHeight();
		if (w > maxNoOfPoints) {
			maxNoOfPoints = w;
		}
		// set background
		g.setColor(Color.black);
		g.fillRect(0, 0, w, h);

		// draw a line
		g.setColor(Color.white);
		int line = h / 2;
		g.drawLine(0, h - line, w, h - line);
		if (points.size() > 1) {
			int maxDrawingPoint = w;
			// draw graph
			g.setColor(Color.red);
			Point base = points.get(0);
			for (int i = 0; (i < points.size() - 1 && i < maxDrawingPoint); i++) {
				Point p1 = points.get(i);
				Point p2 = points.get(i + 1);
				int x1 = 10 + i;
				int x2 = 10 + i + 1;
				int y1 = h - (int) ((p1.getRate() - base.getRate()) * 50000)
						- line;
				int y2 = h - (int) ((p2.getRate() - base.getRate()) * 50000)
						- line;

				Trade trade1 = map.get(p1);
				if (trade1 != null) {
					// set color
					drawTrade(g, x1, y1, trade1);
				} else {
					g.setColor(Color.red);
				}
				g.drawLine(x1, y1, x2, y2);

			}
		}
	}

	public void newPoint(Point p) {
		addPoint(p);

	}

	public void endOfData() {

	}

	void addTradingPoint(TradingPoint p) {
		map.put(p.point, p.trade);
		repaint();
	}

	public void onGoingLong(Trade trade, double budget) {

		TradingPoint p = new TradingPoint(trade.getOpeningPoint(), trade);
		addTradingPoint(p);
	}

	public void onGoingShort(Trade trade, double budget) {

		TradingPoint p = new TradingPoint(trade.getOpeningPoint(), trade);
		addTradingPoint(p);
	}

	public void onPositionClosed(Trade trade, double budget) {

		TradingPoint p = new TradingPoint(trade.getClosingPoint(), trade);
		addTradingPoint(p);
	}

	void drawTrade(Graphics g, int x, int y, Trade trade) {

		if (trade.getState() == State.OPEN) {
			if (trade.getDirection() == Direction.LONG) {
				g.setColor(Color.green);
				// g.drawString("l", x, y);
			} else {
				g.setColor(Color.yellow);
				// g.drawString("s", x, y);
			}
		} else {
			g.setColor(Color.white);
			// g.drawString("c", x, y);
		}
	}

	class TradingPoint {
		Point point;
		Trade trade;

		public TradingPoint(Point point, Trade trade) {
			super();
			this.point = point;
			this.trade = trade;
		}

	}

	class PointAdder implements Runnable {

		private Queue<Point> queue = new LinkedList<Point>();

		public synchronized void queue(Point p) {
			queue.add(p);
			notify();
		}

		public void clear(){
			queue.clear();
		}
		public void run() {
			while (true) {
				Point p = null;
				synchronized (this) {
					while (queue.size() == 0) {
						try {
							wait();
						} catch (InterruptedException ie) {
						}
					}
					p = queue.poll();
				}
				if (p != null) {
					synchronized (p) {
						while (p.isInView()) {
							try {
								p.wait();
							} catch (InterruptedException ie) {
							}
						}
					}
					while(points.size()>maxNoOfPoints){
						points.remove(0);
					}
					points.add(p);
				}
			}

		}

	}

}
